package com.core.workflow.controller;

import com.core.workflow.TaskVo;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Model;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@RestController
@RequestMapping("demo")
public class DemoController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    @GetMapping("test")
    public Object test() {
        Authentication.setAuthenticatedUserId("hwtong-----");
        // 启动流程实例
        String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();

        // 获取第一个任务
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
        for (Task task : tasks) {
            System.out.println("Following task is available for accountancy group: " + task.getName());

            // 申领任务
            taskService.claim(task.getId(), "fozzie");
        }

        // 验证Fozzie获取了任务
        tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
        for (Task task : tasks) {
            System.out.println("Task for fozzie: " + task.getName());

            // 完成任务
            taskService.complete(task.getId());
        }

        System.out.println("Number of tasks for fozzie: "
                + taskService.createTaskQuery().taskAssignee("fozzie").count());

        // 获取并申领第二个任务
        tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
        for (Task task : tasks) {
            System.out.println("Following task is available for management group: " + task.getName());
            taskService.claim(task.getId(), "kermit");
        }

        // 完成第二个任务并结束流程
        for (Task task : tasks) {
            taskService.complete(task.getId());
        }

        // 验证流程已经结束
        HistoricProcessInstance historicProcessInstance =
                historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());

        return null;
    }

    /**
     * 启动流程.
     *
     * @param processKey
     * @param userId
     * @return
     */
    @GetMapping("start")
    public Object startProcessInstance(@RequestParam String processKey, @RequestParam String userId) {

        // 设置流程发起人
        Authentication.setAuthenticatedUserId(userId);
        // 启动流程实例
        return runtimeService.startProcessInstanceByKey(processKey).getId();
    }

    /**
     * 组内待办任务.
     *
     * @param name
     * @return
     */
    @GetMapping("tasks/group")
    public Object groupTasks(@RequestParam String name) {

        // 获取第一个任务
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup(name).orderByTaskCreateTime().desc().list();
        return getTaskVos(tasks);

    }

    private List<TaskVo> getTaskVos(List<Task> tasks) {
        List<TaskVo> vos = new ArrayList<>(tasks.size());
        for (Task task : tasks) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            vos.add(new TaskVo().setName(task.getName())
                    .setId(task.getId())
                    .setOwner(task.getOwner())
                    .setProcessInstanceId(task.getProcessInstanceId())
                    .setTaskDefinitionKey(task.getTaskDefinitionKey())
                    .setProcessInstanceName(processInstance.getProcessDefinitionName())
                    .setStartUserId(processInstance.getStartUserId())
                    .setProcessDefinitionId(processInstance.getProcessDefinitionId())
                    .setStartTime(processInstance.getStartTime()));

        }
        return vos;
    }

    /**
     * 认领任务.
     *
     * @param taskId
     * @param user
     * @return
     */
    @GetMapping("claim")
    public Object claim(@RequestParam String taskId, @RequestParam String user) {
        taskService.claim(taskId, user);
        return "ok";
    }

    /**
     * 用户待办任务.
     *
     * @param name
     * @return
     */
    @GetMapping("tasks/user")
    public Object userTasks(@RequestParam String name) {

        List<Task> tasks = taskService.createTaskQuery().taskAssignee(name).orderByTaskCreateTime().desc().list();

        return getTaskVos(tasks);
    }

    /**
     * 完成流程实例.
     *
     * @param taskId
     * @return
     */
    @GetMapping("complete")
    public Object complete(@RequestParam String taskId) {
        taskService.complete(taskId);

        return null;
    }

    /**
     * 由我发起的流程实例.
     *
     * @return
     */
    @GetMapping("myHistoric")
    public Object startProcessInstance(@RequestParam String user) {

        return historyService.createHistoricProcessInstanceQuery()
                .startedBy(user).orderByProcessInstanceStartTime().desc().list();
    }

    /**
     * 全部活动着色.
     * @param response
     * @param instId
     * @param defId
     * @throws Exception
     */
    @RequestMapping(value = "diagram1")
    public void diagram1(HttpServletResponse response, String instId, String defId) throws Exception {
        List<HistoricActivityInstance> activityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(instId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> activties = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (HistoricActivityInstance activityInstance : activityInstances) {
            if ("sequenceFlow".equals(activityInstance.getActivityType())) {
                //需要高亮显示的连接线
                flows.add(activityInstance.getActivityId());
            } else {
                //需要高亮显示的节点
                activties.add(activityInstance.getActivityId());
            }
        }

        BpmnModel bpmnModel = repositoryService.getBpmnModel(defId);

        ProcessEngineConfiguration engconf = ProcessEngines.getDefaultProcessEngine().getProcessEngineConfiguration();
        //获得图片流
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream inputStream = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                activties,
                flows,
                engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(),
                1.0,
                false);
        //输出图片
//        IOUtils.copy(inputStream, response.getOutputStream());
//        response.setHeader("Content-Disposition", "attachment; filename=" + bpmnModel.getMainProcess().getId() + ".png");
//        response.flushBuffer();
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = response.getOutputStream();
            while ((legth = inputStream.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (out != null) {
                out.close();
            }
        }

    }

    /**
     * 当前活动着色.
     * @param response
     * @param instId
     * @param defId
     * @throws Exception
     */
    @RequestMapping(value = "diagram2")
    public void diagram2(HttpServletResponse response, String instId, String defId) throws Exception {

        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(instId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        BpmnModel bpmnModel = repositoryService.getBpmnModel(defId);
        //获得图片流
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                activityIds,
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体",
                null,
                1.0,
                false);
        //输出图片
//        IOUtils.copy(inputStream, response.getOutputStream());
//        response.setHeader("Content-Disposition", "attachment; filename=" + bpmnModel.getMainProcess().getId() + ".png");
//        response.flushBuffer();
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = response.getOutputStream();
            while ((legth = inputStream.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (out != null) {
                out.close();
            }
        }

    }

}
